﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;


[CustomEditor(typeof(Animator))]
public class Animator_Inspector : Editor
{
	//#if UNITY_5
	Dictionary<string, float> anipos = new Dictionary<string, float>();
	DateTime last = DateTime.Now;
	float timer = 0;
	bool bFuncSrc = true;
	bool bFuncSplit = true;
	bool bFuncAni = true;
	public UnityEngine.Object objQte;
	public UnityEngine.Object objRole;
	public override void OnInspectorGUI()
	{
		if (this.target == null) return;

		bFuncSrc = GUILayout.Toggle(bFuncSrc, "====原生功能====");
		if (bFuncSrc)
		{
			base.OnInspectorGUI();
			GUILayout.Space(16);
		}
		if (Application.isPlaying) return;

		bFuncAni = GUILayout.Toggle(bFuncAni, "====动画功能====");
		if (bFuncAni)
		{
			//EditorGUILayout.HelpBox("这里增加一个Inspector,用来检查动画", MessageType.Info);
			EditorGUILayout.HelpBox("你只需要把所有的动画拖入一个controller就行了，然后我们就会导出他", MessageType.Info);
			//GUILayout.Label("1:" + this.serializedObject);
			//GUILayout.Label("2:" + this.target);
			//return;
			var ani = target as Animator;

			{

				List<AnimationClip> clips = new List<AnimationClip>();
				//if (GUILayout.Button("Update Clips"))
				//{
				#if UNITY_5
				UnityEditor.Animations.AnimatorController cc = ani.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
				#else
				UnityEditorInternal.AnimatorController cc = ani.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
				#endif
				if (cc != null)
				{
					FindAllAniInControl(cc, clips);

					GUILayout.Label("拥有动画:" + clips.Count);
					//}
					foreach (var c in clips)
					{
						if (c == null) continue;
						GUILayout.BeginHorizontal();
						GUILayout.Label(c.name + "(" + c.length * c.frameRate + ")" + (c.isLooping ? "loop" : ""));
						GUILayout.EndHorizontal();
						if (anipos.ContainsKey(c.name) == false)
						{
							anipos[c.name] = 0;
						}
						float v = anipos[c.name];
						v = GUILayout.HorizontalSlider(v, 0, c.length);
						if (v != anipos[c.name])
						{
							Debug.Log("setani");
							anipos[c.name] = v;
							ani.Play(mapClip2State[c.name], 0, v / c.length);
							ani.updateMode = AnimatorUpdateMode.UnscaledTime;
							ani.Update(0);// 0.001f);

						}
					}

				}
			}
		}
		GUILayout.BeginHorizontal ();
		GUILayout.TextArea ("主角");
		objRole = EditorGUILayout.ObjectField (objRole, typeof(UnityEngine.Object), true);
		GUILayout.EndHorizontal ();
		GUILayout.BeginHorizontal ();
		GUILayout.TextArea ("QTE");
		objQte = EditorGUILayout.ObjectField (objQte, typeof(UnityEngine.Object), true);
		GUILayout.EndHorizontal ();
	}



	static Dictionary<string, string> mapClip2State = new Dictionary<string, string>();
	#if UNITY_5
	public static void FindAllAniInControl(UnityEditor.Animations.AnimatorController control, List<AnimationClip> list)
	{
		mapClip2State.Clear();
		for (int i = 0; i < control.layers.Length; i++)
		{
			var layer = control.layers[i];
			FindAllAniInControlMachine(layer.stateMachine, list);
		}
	}
	static void FindAllAniInControlMachine(UnityEditor.Animations.AnimatorStateMachine machine, List<AnimationClip> list)
	{
		for (int i = 0; i < machine.states.Length; i++)
		{
			var s = machine.states[i].state;
			var m = s.motion;
			if (m != null)
			{
				if (list.Contains(m as AnimationClip) == false)
				{
					list.Add(m as AnimationClip);
					if (m.name != s.name)
					{
						//Debug.LogWarning("发现一个问题，clipname 和 state name 不相等 " + m.name + "=>" + s.name);
					}
					mapClip2State[m.name] = s.name;//建立一张转换表，把clip的名字转换为state的名字，以正常clone

				}
			}
		}
		for (int i = 0; i < machine.stateMachines.Length; i++)
		{
			var m = machine.stateMachines[i].stateMachine;
			FindAllAniInControlMachine(m, list);
		}
	}
	#else
	public static void FindAllAniInControl(UnityEditorInternal.AnimatorController control, List<AnimationClip> list)
	{
	mapClip2State.Clear();
	for (int i = 0; i < control.layerCount; i++)
	{
	var layer = control.GetLayer(i);
	FindAllAniInControlMachine(layer.stateMachine, list);
	}
	}
	static void FindAllAniInControlMachine(UnityEditorInternal.StateMachine machine, List<AnimationClip> list)
	{
	for (int i = 0; i < machine.stateCount; i++)
	{
	var s = machine.GetState(i);
	var m = s.GetMotion();
	if (m != null)
	{
	if (list.Contains(m as AnimationClip) == false)
	{
	list.Add(m as AnimationClip);
	if (m.name != s.name)
	{
	//Debug.LogWarning("发现一个问题，clipname 和 state name 不相等 " + m.name + "=>" + s.name);
	}
	mapClip2State[m.name] = s.name;//建立一张转换表，把clip的名字转换为state的名字，以正常clone

	}
	}
	}
	for (int i = 0; i < machine.stateMachineCount; i++)
	{
	var m = machine.GetStateMachine(i);
	FindAllAniInControlMachine(m, list);
	}
	}
	#endif





	////for 动画拆解
	int maxbone = 20;
	void OnGUI_Split()
	{

		Animator a = target as Animator;
		SkinnedMeshRenderer[] rs = a.GetComponentsInChildren<SkinnedMeshRenderer>();
		List<Transform> totalbones = new List<Transform>();

		foreach (var r in rs)
		{
			foreach (var b in r.bones)
			{
				if (totalbones.Contains(b) == false)
					totalbones.Add(b);
			}
		}
		GUILayout.Label("bone for all:" + totalbones.Count);
		maxbone = EditorGUILayout.IntField("max bone for one part:", maxbone);
		GUILayout.Label("has part:" + rs.Length);
		foreach (var r in rs)
		{
			GUILayout.BeginHorizontal();
			GUILayout.Label("part bone:" + r.bones.Length + "||" + r.name, GUILayout.Width(250));
			if (r.bones.Length > maxbone)
			{
				if (GUILayout.Button("split the part", GUILayout.Width(100)))
				{
					DoSplit(maxbone, r);
				}
			}
			GUILayout.EndHorizontal();
		}
	}
	public static void DoSplit(int maxbone, SkinnedMeshRenderer srcr)
	{
		SkinMesh src = new SkinMesh();
		src.bone = new List<Transform>(srcr.bones);
		src.mesh = srcr.sharedMesh;
		var ss = SplitSkinMesh(maxbone, src);
		if (ss.Count > 0)
		{
			srcr.sharedMesh = ss[0].mesh;
			srcr.bones = ss[0].bone.ToArray();
		}
		for (int i = 1; i < ss.Count; i++)
		{
			GameObject newsplit = new GameObject();
			newsplit.name = srcr.name + "_" + i;
			newsplit.transform.parent = srcr.transform.parent;
			newsplit.transform.localPosition = srcr.transform.localPosition;
			newsplit.transform.localScale = srcr.transform.localScale;
			newsplit.transform.localRotation = srcr.transform.localRotation;

			var nr = newsplit.AddComponent<SkinnedMeshRenderer>();
			nr.rootBone = srcr.rootBone;
			nr.sharedMesh = ss[i].mesh;
			nr.bones = ss[i].bone.ToArray();
			nr.sharedMaterials = srcr.sharedMaterials;

		}
	}
	class SkinMesh
	{
		public List<Transform> bone;
		public Mesh mesh;
	}
	static List<SkinMesh> SplitSkinMesh(int maxbone, SkinMesh srcmesh)
	{
		List<SkinMesh> splitmesh = new List<SkinMesh>();//拆解的模型
		List<int> seeks = new List<int>();//每个子模型的处理进度
		if (srcmesh == null || srcmesh.mesh == null) {
			splitmesh.Add (srcmesh);
			return splitmesh;
		}
		Debug.Log("submesh=" + srcmesh.mesh.subMeshCount);
		for (int s = 0; s < srcmesh.mesh.subMeshCount; s++)
		{
			seeks.Add(0);
		}
		for (int loopcount = 0; loopcount < 100; loopcount++)//死循环，一直到处理完跳出
		{
			var m = new SkinMesh();
			FillSkinMesh(srcmesh, maxbone, seeks, m);
			splitmesh.Add(m);

			bool bexit = true;//检验是否满足退出条件
			for (int s = 0; s < seeks.Count; s++)
			{
				if (seeks[s] < srcmesh.mesh.GetIndices(s).Length)
				{
					bexit = false;
					break;
				}
			}
			if (bexit) break;
		}
		//Debug.Log("split to:" + splitmesh.Count);

		for (int i = 0; i < splitmesh.Count; i++) {
			if(splitmesh.Count>1)
			{
				splitmesh [i].mesh.name = srcmesh.mesh.name + "_" + i;
			}
			else
			{
				splitmesh [i].mesh.name = srcmesh.mesh.name;
			}
		}
		return splitmesh;
	}

	static void FillSkinMesh(SkinMesh srcmesh, int maxbone, List<int> seek, SkinMesh outmesh)
	{
		outmesh.bone = new List<Transform>();
		outmesh.mesh = new Mesh();
		Dictionary<int, int> indexmap = new Dictionary<int, int>();
		Dictionary<int, int> bonemap = new Dictionary<int, int>();
		List<Vector3> poses = new List<Vector3>();
		List<Vector3> normal = new List<Vector3>();
		List<Vector2> uv = new List<Vector2>();
		List<Vector2> uv2 = null;
		List<Vector2> uv3 = null;
		List<Color32> color = null;
		List<BoneWeight> skininfo = new List<BoneWeight>();
		List<Matrix4x4> tpose = new List<Matrix4x4>();

		List<List<int>> subindexs = new List<List<int>>();
		for (int s = 0; s < seek.Count; s++)
		{
			subindexs.Add(new List<int>());
		}
		//拆分逻辑
		for (int loopcount = 0; loopcount < 100000; loopcount++)//死循环，直到超出限制
		{
			bool bexit = true;
			for (int s = 0; s < seek.Count; s++)
			{
				var subindex = subindexs[s];
				var si = srcmesh.mesh.GetIndices(s);
				if (si.Length > seek[s])//有才处理
				{
					bexit = false;
					for (int i = 0; i < 3; i++)//一次处理一个三角形
					{
						int srcindex = si[seek[s] + i];
						if (indexmap.ContainsKey(srcindex) == false)//新顶点
						{
							indexmap[srcindex] = poses.Count;
							poses.Add(srcmesh.mesh.vertices[srcindex]);
							normal.Add(srcmesh.mesh.normals[srcindex]);
							if (srcmesh.mesh.uv != null && srcmesh.mesh.uv.Length > 0)
							{
								if (uv == null) uv = new List<Vector2>();
								uv.Add(srcmesh.mesh.uv[srcindex]);
							}
							#if UNITY_5
							if (srcmesh.mesh.uv2 != null && srcmesh.mesh.uv2.Length > 0)
							{
								if (uv2 == null) uv2 = new List<Vector2>();
								uv2.Add(srcmesh.mesh.uv2[srcindex]);
							}
							if (srcmesh.mesh.uv3 != null && srcmesh.mesh.uv3.Length > 0)
							{
								if (uv3 == null) uv3 = new List<Vector2>();
								uv3.Add(srcmesh.mesh.uv3[srcindex]);
							}
							#else
							if (srcmesh.mesh.uv1 != null && srcmesh.mesh.uv1.Length > 0)
							{
							if (uv2 == null) uv2 = new List<Vector2>();
							uv2.Add(srcmesh.mesh.uv1[srcindex]);
							}
							if (srcmesh.mesh.uv2 != null && srcmesh.mesh.uv2.Length > 0)
							{
							if (uv3 == null) uv3 = new List<Vector2>();
							uv3.Add(srcmesh.mesh.uv2[srcindex]);
							}
							#endif
							if (srcmesh.mesh.colors32 != null && srcmesh.mesh.colors32.Length > 0)
							{
								if (color == null) color = new List<Color32>();
								color.Add(srcmesh.mesh.colors32[srcindex]);
							}

							BoneWeight bw = srcmesh.mesh.boneWeights[srcindex];
							bw.boneIndex0 = TestBone(srcmesh, outmesh, tpose, bonemap, bw.boneIndex0);
							bw.boneIndex1 = TestBone(srcmesh, outmesh, tpose, bonemap, bw.boneIndex1);
							bw.boneIndex2 = TestBone(srcmesh, outmesh, tpose, bonemap, bw.boneIndex2);
							bw.boneIndex3 = TestBone(srcmesh, outmesh, tpose, bonemap, bw.boneIndex3);
							skininfo.Add(bw);
						}
						subindex.Add(indexmap[srcindex]);

					}
					seek[s] = seek[s] + 3;
				}
			}
			//加上骨骼的处理，终止条件改为骨骼数超越限制
			if (outmesh.bone.Count >= maxbone)
			{
				Debug.LogWarning("==break at:" + maxbone + "/" + outmesh.bone.Count);
				break;
			}
			else if (bexit)
			{
				Debug.LogWarning("==break for end.");
				break;
			}
		}
		#if UNITY_5
		outmesh.mesh.SetVertices(poses);
		outmesh.mesh.SetNormals(normal);
		if (uv != null) outmesh.mesh.SetUVs(0, uv);
		if (uv2 != null) outmesh.mesh.SetUVs(1, uv2);
		if (uv3 != null) outmesh.mesh.SetUVs(2, uv3);
		if (color != null) outmesh.mesh.SetColors(color);
		#else
		outmesh.mesh.vertices = poses.ToArray();
		outmesh.mesh.normals = normal.ToArray();
		if (uv != null) outmesh.mesh.uv = uv.ToArray();
		if (uv2 != null) outmesh.mesh.uv1 = uv2.ToArray();
		if (uv3 != null) outmesh.mesh.uv2 = uv3.ToArray();
		if (color != null) outmesh.mesh.colors32 = color.ToArray();
		#endif
		outmesh.mesh.subMeshCount = subindexs.Count;
		for (int i = 0; i < subindexs.Count; i++)
		{
			outmesh.mesh.SetTriangles(subindexs[i].ToArray(), i);
		}

		outmesh.mesh.boneWeights = skininfo.ToArray();

		outmesh.mesh.bindposes = tpose.ToArray();
		Debug.LogWarning("outmest.mesh" + outmesh.mesh.vertexCount + "," + outmesh.bone.Count + "," + outmesh.mesh.bindposes.Length);
		foreach (var b in outmesh.bone)
		{
			Debug.LogWarning("bone=" + b);
		}
	}

	private static int TestBone(SkinMesh srcmesh, SkinMesh outmesh, List<Matrix4x4> tpose, Dictionary<int, int> bonemap, int bone)
	{
		if (bone >= 0)
		{
			if (bonemap.ContainsKey(bone) == false)//addbone
			{
				bonemap[bone] = outmesh.bone.Count;
				outmesh.bone.Add(srcmesh.bone[bone]);
				tpose.Add(srcmesh.mesh.bindposes[bone]);
			}
			return bonemap[bone];
		}
		else
			return -1;
	}
	//#endif
}

